package com.demo.service.system.impl;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.demo.dto.Pager;
import com.demo.enums.BizExceptionEnum;
import com.demo.exception.ServiceLayerException;
import com.demo.mapper.system.AdminMapper;
import com.demo.model.system.Admin;
import com.demo.model.system.AdminExample;
import com.demo.model.system.Permission;
import com.demo.model.system.PermissionExample;
import com.demo.model.system.Resource;
import com.demo.model.system.ResourceExample;
import com.demo.model.system.Role;
import com.demo.service.system.AdminService;
import com.demo.service.system.PermissionService;
import com.demo.service.system.ResourceService;
import com.google.common.base.Function;
import com.google.common.collect.Lists;

@Service
public class AdminServiceImpl implements AdminService {

	@Autowired
	AdminMapper mapper;
	
	@Autowired
	ResourceService resourceService;
	
	@Autowired
	PermissionService permissionService;
	
	@Override
	@Transactional
	public int add(Admin record) throws ServiceLayerException {
		if (null == record) {
			throw new ServiceLayerException(BizExceptionEnum.PARAM_NULL);
		}		
		return mapper.insert(record);
	}

	@Override
	@Transactional
	public int update(Admin record) throws ServiceLayerException {
		if (null == record) {
			throw new ServiceLayerException(BizExceptionEnum.PARAM_NULL);
		}		
		if (null == record.getId()) {
			throw new ServiceLayerException(BizExceptionEnum.PARAM_DTO_ID_NULL);
		}
		return mapper.updateByPrimaryKeySelective(record);
	}

	@Override
	@Transactional
	public int enable(List<Integer> ids) throws ServiceLayerException {
		if (null == ids) {
			throw new ServiceLayerException(BizExceptionEnum.PARAM_NULL);
		}		
		if (0 == ids.size()) {
			throw new ServiceLayerException(BizExceptionEnum.PARAM_LIST_EMPTY);
		}
		AdminExample example = new AdminExample();
		example.or().andIdIn(ids);
		Admin record = new Admin();
		record.setStoreStatus(Boolean.TRUE);
		return mapper.updateByExampleSelective(record, example);
	}

	@Override
	@Transactional
	public int disable(List<Integer> ids) throws ServiceLayerException {
		if (null == ids) {
			throw new ServiceLayerException(BizExceptionEnum.PARAM_NULL);
		}		
		if (0 == ids.size()) {
			throw new ServiceLayerException(BizExceptionEnum.PARAM_LIST_EMPTY);
		}		
		AdminExample example = new AdminExample();
		example.or().andIdIn(ids);
		Admin record = new Admin();
		record.setStoreStatus(Boolean.FALSE);
		return mapper.updateByExampleSelective(record, example);
	}

	@Override
	public Admin getById(Integer id) throws ServiceLayerException {
		if (null == id) {
			throw new ServiceLayerException(BizExceptionEnum.PARAM_NULL);
		}		
		return mapper.selectByPrimaryKey(id);
	}

	@Override
	public List<Admin> findByCondition(AdminExample example) {
		return mapper.selectByExample(example);
	}

	@Override
	public int getCount(AdminExample example) {
		return mapper.countByExample(example);
	}

	@Override
	public Pager<Admin> findByPage(AdminExample example, Pager<Admin> pager) throws ServiceLayerException {
		if (null == pager) {
			throw new ServiceLayerException(BizExceptionEnum.PARAM_NULL);
		}
		RowBounds rowBounds = new RowBounds(pager.getStart(), pager.getRows());
		pager.setData(mapper.selectByExample(example, rowBounds));
		pager.setTotalRow(mapper.countByExample(example));
		return pager;
	}

	@Override
	public Admin getWithRolesById(Integer id) throws ServiceLayerException {
		if (null == id) {
			throw new ServiceLayerException(BizExceptionEnum.PARAM_NULL);
		}		
		return mapper.getWithRolesById(id);
	}

	@Override
	@Transactional
	public int resetPwd(Admin admin) throws ServiceLayerException {
		if (null == admin) {
			throw new ServiceLayerException(BizExceptionEnum.PARAM_NULL);
		}		
		if (null == admin.getId()) {
			throw new ServiceLayerException(BizExceptionEnum.PARAM_DTO_ID_NULL);
		}		
		if (StringUtils.isEmpty(admin.getPwd())) {
			throw new ServiceLayerException(BizExceptionEnum.PARAM_DTO_PWD_EMPTY);
		}		
		Admin target = new Admin();
		List<String> properties  = Arrays.asList("id","pwd","salt","modifyAdminName","modifyTime");
		for (Iterator<String> iterator = properties.iterator(); iterator.hasNext();) {
			String name = iterator.next();
			try {
				BeanUtils.copyProperty(target, name, admin);
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}
		return mapper.updateByPrimaryKeySelective(target);
	}

	@Override
	public Admin getWithResourcesById(Integer id) throws ServiceLayerException {
		if (null == id) {
			throw new ServiceLayerException(BizExceptionEnum.PARAM_NULL);
		}
		//管理员的权限信息包括两部分:其一是管理员自身绑定的权限，其二是管理员的角色拥有的权限
		PermissionExample permissionExample = new PermissionExample();
		//其一是管理员自身绑定的权限
		permissionExample.or().andStoreStatusEqualTo(Boolean.TRUE).andAdminIdEqualTo(id);
		
		//查询管理员的角色列表
		Admin admin = getWithRolesById(id);
		if (null != admin.getRoles() && admin.getRoles().size() > 0) {
			List<Integer> roleIdList = Lists.transform(admin.getRoles(), new Function<Role, Integer>(){
				
				@Override
				public Integer apply(Role role) {
					return role.getId();
				}
				
			});
			//其二是管理员的角色拥有的权限
			permissionExample.or().andStoreStatusEqualTo(Boolean.TRUE).andRoleIdIn(roleIdList);
		}
		List<Permission> permissionList = permissionService.findByCondition(permissionExample);
		
		//查询到管理员的权限中间表记录之后，进一步查询权限实体列表
		if (null != permissionList && permissionList.size() > 0) {
			List<Integer> resourceIdList = Lists.transform(permissionList, new Function<Permission, Integer>(){
				
				@Override
				public Integer apply(Permission permission) {
					return permission.getResourceId();
				}
				
			});
			ResourceExample resourceExample = new ResourceExample();
			resourceExample.or().andStoreStatusEqualTo(Boolean.TRUE).andIdIn(resourceIdList);
			List<Resource> resources = resourceService.findByCondition(resourceExample);
			admin.setResources(resources);
		}
		return admin;
	}

}
